Schema validation with static type inference
flowchart TD
Schema -->|codecFor| Codec
Schema -->|guardFor| Guard
Schema -->|arbitraryFor| Arbitrary
Schema -->|prettyFor| Pretty
Features
- deriving single artifacts from a
Schema
:
Codec
Guard
Arbitrary
Pretty
Codec
(all in one artifact)- custom interpreters
- custom schema combinators
- custom data types
- custom decode errors
- versioning (TODO)
- migration (TODO)
Summary
import * as C from "@fp-ts/schema/Codec";
const Person = C.struct({
name: C.string,
age: C.number,
});
type Person = C.Infer<typeof Person>;
import * as DE from "@fp-ts/schema/DecodeError";
expect(Person.decode({ name: "name", age: 18 })).toEqual(
C.success({ name: "name", age: 18 })
);
expect(Person.decode(null)).toEqual(
C.failure(DE.notType("{ readonly [_: string]: unknown }", null))
);
expect(Person.encode({ name: "name", age: 18 })).toEqual({
name: "name",
age: 18,
});
expect(Person.is({ name: "name", age: 18 })).toEqual(true);
expect(Person.is(null)).toEqual(false);
expect(Person.pretty({ name: "name", age: 18 })).toEqual(
'{ "name": "name", "age": 18 }'
);
import * as fc from "fast-check";
console.log(fc.sample(Person.arbitrary(fc), 2));
Custom interpreters
src/Pretty.ts
, src/Guard.ts
and src/Arbitrary.ts
are good examples of defining a custom interpreter.
Custom schema combinators
Examples in /src/Schema.ts
.
All the combinators defined in /src/Schema.ts
could be implemented in userland.
Custom data types
Examples in /src/data/*
Understanding Schemas
A schema is a description of a data structure that can be used to generate various artifacts from a single declaration.
Guard
A Guard
is a derivable artifact that is able to refine a value of type unknown
to a value of type A
.
interface Guard<A> extends Schema<A> {
readonly is: (input: unknown) => input is A;
}
Arbitrary
An Arbitrary
is a derivable artifact that is able to produce fast-check
arbitraries.
interface Arbitrary<in out A> extends Schema<A> {
readonly arbitrary: (fc: typeof FastCheck) => FastCheck.Arbitrary<A>;
}
Pretty
A Pretty
is a derivable artifact that is able to pretty print a value of type A
.
interface Pretty<in out A> extends Schema<A> {
readonly pretty: (a: A) => string;
}
Codec
A Codec
is a derivable artifact that is able to:
- decode a value of type
unknown
to a value of type A
. - encode a value of type
A
to a value of type unknown
.
interface Codec<in out A>
extends Schema<A>,
Decoder<unknown, A>,
Encoder<unknown, A>,
Guard<A>,
Arbitrary<A>,
Pretty<A> {}
Basic usage
Primitives
import * as C from "@fp-ts/schema/Codec";
C.string;
C.number;
C.boolean;
C.bigint;
C.symbol;
C.unknown;
C.any;
Filters
pipe(C.string, C.minLength(1));
pipe(C.string, C.maxLength(10));
pipe(C.number, C.lessThan(0));
pipe(C.number, C.lessThanOrEqualTo(0));
pipe(C.number, C.greaterThan(10));
pipe(C.number, C.greaterThanOrEqualTo(10));
pipe(C.number, C.int);
Literals
C.literal("a");
C.literal("a", "b", "c");
Native enums
enum Fruits {
Apple,
Banana,
}
C.nativeEnum(Fruits);
Unions
C.union(C.string, C.number);
Tuples
C.tuple(C.string, C.number);
Rest element
pipe(C.tuple(C.string, C.number), C.withRest(C.boolean));
Arrays
C.array(C.number);
Non empty arrays
C.nonEmptyArray(C.number);
Structs
C.struct({ a: C.string, b: C.number });
Optional fields
C.struct({ a: C.string, b: C.number }, { c: C.boolean });
Pick
pipe(C.struct({ a: C.string, b: C.number }), C.pick("a"));
Omit
pipe(C.struct({ a: C.string, b: C.number }), C.omit("a"));
Partial
C.partial(C.struct({ a: C.string, b: C.number }));
String index signature
C.stringIndexSignature(C.string);
Symbol index signature
C.symbolIndexSignature(C.string);
Extend
pipe(
C.struct({ a: C.string, b: C.string }),
C.extend(C.stringIndexSignature(C.string))
);
Option
C.option(C.number);
ReadonlySet
C.readonlySet(C.number);
Chunk
C.chunk(C.number);
List
C.list(C.number);
Documentation
License
The MIT License (MIT)